home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / devices / msh_1_5 / part06 < prev   
Internet Message Format  |  1990-02-21  |  52KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i084: MSH 1.5 - Messydos File System Handler , Part06/06
  5. Message-ID: <11503@xanth.cs.odu.edu>
  6. Date: 21 Feb 90 02:03:02 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: Olaf 'Rhialto' Seibert <U211344%HNYKUN11.BITNET@CUNYVM.CUNY.EDU>
  9. Lines: 1937
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11. X-Mail-Submissions-To: Amiga@cs.odu.edu
  12. X-Post-Discussions-To: comp.sys.amiga
  13.  
  14. Submitted-by: Olaf 'Rhialto' Seibert <U211344%HNYKUN11.BITNET@CUNYVM.CUNY.EDU>
  15. Posting-number: Volume 90, Issue 084
  16. Archive-name: devices/msh-1.5/part06
  17.  
  18. #!/bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 6 (of 6)."
  25. # Contents:  src/devio.c
  26. # Wrapped by tadguy@xanth on Tue Feb 20 20:57:14 1990
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'src/devio.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'src/devio.c'\"
  30. else
  31. echo shar: Extracting \"'src/devio.c'\" \(47667 characters\)
  32. sed "s/^X//" >'src/devio.c' <<'END_OF_FILE'
  33. X/*-
  34. X * $Id: devio.c,v 1.4 90/02/10 21:42:17 Rhialto Exp $
  35. X * $Log:    devio.c,v $
  36. X * Revision 1.4  90/02/10  21:42:17  Rhialto
  37. X * Small changes
  38. X * 
  39. X * Revision 1.3  90/01/27  20:36:04  Rhialto
  40. X * Variable #sectors/track!
  41. X *
  42. X * Revision 1.2  90/01/23  00:41:39  Rhialto
  43. X * Remove C version of DecodeTrack.
  44. X *
  45. X * Revision 1.1  89/12/17  20:04:11  Rhialto
  46. X *
  47. X * DEVIO.C
  48. X *
  49. X * The messydisk.device code that does the real work.
  50. X *
  51. X * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  52. X * not be used or copied without a licence.
  53. X-*/
  54. X
  55. X#include "dev.h"
  56. X#include "device.h"
  57. X
  58. X/*#undef DEBUG            /**/
  59. X#ifdef DEBUG
  60. X#   define    debug(x)  dbprintf x
  61. X#else
  62. X#   define    debug(x)
  63. X#endif
  64. X
  65. Xstruct DiskResource *DRResource;/* Argh! A global variable! */
  66. Xvoid *CiaBResource;        /* And yet another! */
  67. X
  68. Xvoid        Internal_Update();
  69. Xword        DataCRC();
  70. Xword        CalculateGapLength();
  71. X
  72. X/*-
  73. X *  The high clock bit in this table is still 0, but it could become
  74. X *  a 1 if the two adjecent data bits are both 0.
  75. X *  In fact, that is the principle of MFM clock bits: make sure that no
  76. X *  two 1 bits are adjecent, but not too many (more than 3) 0 bits either.
  77. X *  So, 0 c 0 -> 0 1 0        (where c is a clock bit to be determined)
  78. X *    0 c 1 -> 0 0 1
  79. X *    1 c 0 -> 1 0 0
  80. X *    1 c 1 -> 1 0 1
  81. X *  The sync pattern, $4489, is %0100 0100 1000 1001
  82. X *                  ~ ~  ~ ~  ~ ~  ~ ~ -> %1010 0001 -> $A1
  83. X *  also follows the rules, but won't be formed by encoding $A1...
  84. X *  Since the bytes are written high bit first, the unknown clock bit
  85. X *  (for encoded nybbles 0-7, high bit 0) will become a 1 if the preceding
  86. X *  byte was even (with low bit 0).
  87. X *  So, the clock bit is the NOR of the two data bits.
  88. X-*/
  89. X
  90. Xbyte        MfmEncode[16] = {
  91. X    0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
  92. X    0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
  93. X};
  94. X
  95. X#define SYNC    0x4489
  96. X#define TLEN    12500        /* In BYTES */
  97. X#define RLEN    (TLEN+1324) /* 1 sector extra */
  98. X#define WLEN    (TLEN+20)   /* 20 bytes more than the theoretical track size */
  99. X
  100. X#define INDEXGAP    60  /* All these values are in WORDS */
  101. X
  102. X#define IDGAP2        12  /* Sector header: 22 words */
  103. X#define IDSYNC         3
  104. X#define IDMARK         1
  105. X#define IDDATA         4
  106. X#define IDCRC         2
  107. X#define IDLEN        (IDGAP2+IDSYNC+IDMARK+IDDATA+IDCRC)
  108. X
  109. X#define DATAGAP1    22  /* Sector itself: 552 words */
  110. X#define DATAGAP2    12
  111. X#define DATASYNC     3
  112. X#define DATAMARK     1
  113. X#define DATACRC      2
  114. X#define DATAGAP3_9    78  /* for 9 or less sectors/track */
  115. X#define DATAGAP3_10    40  /* for 10 sectors/track */
  116. X#define DATALEN     (DATAGAP1+DATAGAP2+DATASYNC+DATAMARK+MS_BPS+DATACRC)
  117. X
  118. X#define BLOCKLEN    (IDLEN+DATALEN)     /* Total: 574 words */
  119. X
  120. X#define TAILGAP     50
  121. X
  122. X/* INDENT OFF */
  123. X#asm
  124. X
  125. X; Some hardware data:
  126. X
  127. XSYNC        equ $4489
  128. XTLEN        equ 12500    ; 2 miscrosecs/bit, 200 ms/track -> 100000 bits
  129. XWLEN        equ TLEN+20
  130. X
  131. X;;;;
  132. X;
  133. X;   The following lengths are all in unencoded bytes (or encoded words)
  134. X
  135. XINDEXGAP    equ 60
  136. X
  137. XIDGAP2        equ 12
  138. XIDSYNC        equ  3
  139. XIDMARK        equ  1
  140. XIDDATA        equ  4
  141. XIDCRC        equ  2
  142. X
  143. XDATAGAP1    equ 22
  144. XDATAGAP2    equ 12
  145. XDATASYNC    equ  3
  146. XDATAMARK    equ  1
  147. XDATACRC     equ  2
  148. X
  149. Xcustom        equ $DFF000
  150. X
  151. XDsklen        equ $24
  152. XIntena        equ $9a     ; Interrupt enable  register (write)
  153. XIntreq        equ $9c     ; Interrupt request register (write)
  154. X
  155. X; Flags in DSKLEN:
  156. X
  157. Xdskdmaoff    equ $4000
  158. X
  159. X; Flags in INTENA/INTREQ:
  160. X
  161. Xintf_setclr    equ 1<<15
  162. Xintf_dskblk    equ 1<<1
  163. X
  164. X; CIA interrupt control register bits/flags:
  165. X
  166. Xciaicrf_flg    equ    1<<4     ; flg interrupt (disk index)
  167. X
  168. X; some cia.resource library functions
  169. X
  170. X        public    _LVOSignal
  171. X        public    _LVOAbleICR
  172. X        public    _LVOSetICR
  173. X
  174. X_SafeEnableICR: move.l    _CiaBResource,a6
  175. X        move.b    4+1(sp),d0
  176. X        jsr    _LVOSetICR(a6)      ; clear pending interrupt
  177. X        move.b    4+1(sp),d0
  178. X        or.b    #$80,d0         ; then enable it
  179. X        jsr    _LVOAbleICR(a6)
  180. X        rts
  181. X;;;;
  182. X;
  183. X;   Disk index interrupt code.
  184. X;   is_Data (A1) is the value to stuff into the DSKLEN register.
  185. X;   A0 points to the custom chips already.
  186. X;   It then enables the disk block interrupt and disables the
  187. X;   index interrupt.
  188. X
  189. X_IndexIntCode:
  190. X;     movem.l A2-A4/D2-D7,-(sp)
  191. X    move.w    #dskdmaoff,Dsklen(a0)
  192. X    move.w    a1,Dsklen(a0)
  193. X    move.w    a1,Dsklen(a0)       ; this enables the DMA
  194. X    move.w    #intf_setclr|intf_dskblk,Intena(a0)
  195. X    move.l    _CiaBResource,a6
  196. X    move.b    #ciaicrf_flg,d0
  197. X    jsr    _LVOAbleICR(a6)     ; disable index interrupt
  198. X;     movem.l (sp)+,A2-A4/D2-D7
  199. X    rts
  200. X;;;;
  201. X;
  202. X;   Disk DMA finished interrupt code.
  203. X;   (a1) is the task to Signal, 4(a1) is the signal mask to use.
  204. X;   Disables the disk block finished interrupt.
  205. X
  206. X_DskBlkIntCode:
  207. X    move.w    #dskdmaoff,Dsklen(a0)   ; disable disk DMA
  208. X    move.w    #intf_dskblk,Intena(a0) ; disable the interrupt
  209. X    move.w    #intf_dskblk,Intreq(a0) ; clear 'diskblock finished' flag
  210. X    move.l    4(a1),d0            ; signal mask
  211. X    move.l    (a1),a1             ; task to signal
  212. X    jsr    _LVOSignal(a6)
  213. X    rts
  214. X
  215. X#endasm
  216. X
  217. X#define DSKDMAEN    (1<<15)
  218. X#define DSKWRITE    (1<<14)
  219. X
  220. Xvoid IndexIntCode(), DskBlkIntCode();
  221. X
  222. X/* INDENT ON */
  223. X
  224. Xint
  225. XHardwareIO(dev, unit, dskwrite)
  226. XDEV           *dev;
  227. Xregister UNIT  *unit;
  228. Xint        dskwrite;
  229. X{
  230. X    struct {
  231. X    struct Task *task;
  232. X    ulong signal;
  233. X    } tasksig;
  234. X
  235. X    debug(("Disk buffer is at %lx\n", dev->md_Rawbuffer));
  236. X
  237. X    tasksig.task = FindTask(NULL);
  238. X    tasksig.signal = 1L << unit->mu_DmaSignal;
  239. X
  240. X    unit->mu_DRUnit.dru_Index.is_Data = (APTR) ((WLEN >> 1)|DSKDMAEN| dskwrite);
  241. X    unit->mu_DRUnit.dru_DiscBlock.is_Data = (APTR) &tasksig;
  242. X
  243. X    /* Clear signal bit */
  244. X    SetSignal(0L, tasksig.signal);
  245. X
  246. X    /* Allocate drive and install index and block interrupts */
  247. X    GetDrive(&unit->mu_DRUnit);
  248. X
  249. X    /* Select correct drive and side */
  250. X    ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR;    /* See hardware manual p229 */
  251. X    ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR
  252. X               & ~(CIAF_DSKSEL0 << unit->mu_UnitNr)
  253. X               & ~(unit->mu_CurrentSide << CIAB_DSKSIDE);
  254. X
  255. X    /* Set up disk parameters */
  256. X
  257. X/*
  258. X * This is the adkcon setup: MFM mode, wordsync, no MSBsync, fast mode.
  259. X * The precomp is 0 nanoseconds for the outer half of the disk, 120 for
  260. X * the rest.
  261. X */
  262. X    {
  263. X    register word adk;
  264. X
  265. X    custom.adkcon = ADKF_PRECOMP1|ADKF_PRECOMP0|ADKF_MSBSYNC;
  266. X
  267. X    adk = ADKF_SETCLR|ADKF_MFMPREC|ADKF_FAST|ADKF_WORDSYNC;
  268. X
  269. X    /* Are we on the inner half ? */
  270. X    if (unit->mu_CurrentTrack > unit->mu_NumCyls >> 1) {
  271. X        adk |= ADKF_PRECOMP0;
  272. X    }
  273. X    custom.adkcon = adk;
  274. X    }
  275. X
  276. X    /* Set up disk buffer address */
  277. X    custom.dskpt = (APTR) dev->md_Rawbuffer;
  278. X
  279. X    /* Enable disk DMA */
  280. X    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_DISK;
  281. X
  282. X    if (dskwrite) {
  283. X    /* Enable disk index interrupt to start the whole thing. */
  284. X    SafeEnableICR((int) CIAICRF_FLG);
  285. X    } else {
  286. X    /* Set the sync word */
  287. X    custom.dsksync = SYNC;
  288. X
  289. X    /* Do the same as the disk index interrupt would */
  290. X    custom.dsklen = DSKDMAOFF;
  291. X    custom.dsklen = (RLEN >> 1) | DSKDMAEN;
  292. X    custom.dsklen = (RLEN >> 1) | DSKDMAEN;
  293. X
  294. X    custom.intena = INTF_SETCLR | INTF_DSKBLK;
  295. X    }
  296. X
  297. X    Wait(tasksig.signal);
  298. X
  299. X    FreeDrive();
  300. X}
  301. X
  302. X#if 0
  303. X#define ID_ADDRESS_MARK     0xFE
  304. X#define MFM_ID            0x5554
  305. X#define DATA_ADDRESS_MARK   0xFB
  306. X#define MFM_DATA        0x5545
  307. X
  308. X/* INDENT OFF
  309. Xbyte
  310. XDecodeByte(mfmdecode, mfm)
  311. Xbyte *mfmdecode;
  312. Xword mfm;
  313. X{
  314. X    return mfmdecode[(byte)mfm & 0x7F] |
  315. X       mfmdecode[(byte)(mfm >> 8) & 0x7F] << 4;
  316. X} */
  317. X
  318. X#asm
  319. Xmfmdecode   set     4
  320. Xmfm        set     8
  321. X
  322. X_DecodeByte:
  323. X    move.l    mfmdecode(sp),a0
  324. X    move.b    mfm(sp),d1      ; high nybble
  325. X    and.w    #$7f,d1     ; strip clock bit (and garbage)
  326. X    move.b    (a0,d1.w),d0    ; decode 4 data bits
  327. X    lsl.b    #4,d0        ; make room for the rest
  328. X
  329. X    move.b    mfm+1(sp),d1    ; low nybble
  330. X    and.b    #$7f,d1     ; strip clock bit again
  331. X    or.b    (a0,d1.w),d0    ; insert 4 decoded bits
  332. X
  333. X    rts
  334. X
  335. X#endasm
  336. X
  337. X/* INDENT ON */
  338. Xbyte DecodeByte();
  339. X
  340. Xint
  341. XDecodeTrack(dev, unit)
  342. XDEV           *dev;
  343. XUNIT           *unit;
  344. X{
  345. X    register word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  346. X    byte       *rawend = (byte *)rawbuf + RLEN - (MS_BPS+2)*sizeof(word);
  347. X    byte       *trackbuf = unit->mu_TrackBuffer;
  348. X    register byte  *decode = dev->md_MfmDecode;     /*  a3 */
  349. X    word       *oldcrc = unit->mu_CrcBuffer;
  350. X    register byte  *secptr;                /*  a4 */
  351. X    long        sector;
  352. X    word        numsecs;
  353. X    register long   numbytes;                /*  d3 */
  354. X    word        maxsec;
  355. X
  356. X#define Len    ((byte *)rawbuf - dev->md_Rawbuffer)
  357. X    maxsec = 0;
  358. X
  359. X    for (numsecs = 0; numsecs < MS_SPT_MAX; numsecs++) {
  360. X    /*
  361. X     *  First try to find a sector id.
  362. X     */
  363. Xfind_id:
  364. X    while (*rawbuf != SYNC) {
  365. X        if (++rawbuf >= rawend) {
  366. X        debug(("id start, EOT %4x\n", Len));
  367. X        goto end;
  368. X        }
  369. X    }
  370. X    while (*rawbuf == SYNC) {
  371. X        rawbuf++;
  372. X    }
  373. X    if (*rawbuf++ != MFM_ID) {
  374. X        debug(("No ID (%4x), %4x\n", rawbuf[-1], Len));
  375. X        goto find_id;
  376. X    }
  377. X
  378. X    sector = DecodeByte(decode, *rawbuf++);
  379. X    if (sector != unit->mu_CurrentTrack) {
  380. X        debug(("Track error?? %d\n", (int)sector));
  381. X        goto find_id;
  382. X    }
  383. X    sector = DecodeByte(decode, *rawbuf++);
  384. X    if (sector != unit->mu_CurrentSide) {
  385. X        debug(("Side error?? %d\n", (int)sector));
  386. X        goto find_id;
  387. X    }
  388. X    if (rawbuf >= rawend) {
  389. X        debug(("id end, EOT %4x\n", Len));
  390. X        goto end;
  391. X    }
  392. X    sector = DecodeByte(decode, *rawbuf++);
  393. X    debug(("#%2d %4x, ", (int)sector, Len-0xC));
  394. X    if (sector > MS_SPT_MAX) {
  395. X        debug(("Bogus sector number) "));
  396. X        goto find_id;
  397. X    }
  398. X    if (sector > maxsec)
  399. X        maxsec = sector;
  400. X    sector--;        /* Normalize sector number */
  401. X
  402. X    /*
  403. X     *  Then find the data block.
  404. X     */
  405. Xfind_data:
  406. X    while (*rawbuf != SYNC) {
  407. X        if (++rawbuf >= rawend) {
  408. X        debug(("data start, EOT %4x\n", Len));
  409. X        return 0; /* TDERR_TooFewSecs; */
  410. X        }
  411. X    }
  412. X    while (*rawbuf == SYNC) {
  413. X        rawbuf++;
  414. X    }
  415. X    if (*rawbuf++ != MFM_DATA) {
  416. X        debug(("No Data (%4x), %4x\n", rawbuf[-1], Len));
  417. X        goto find_id;
  418. X    }
  419. X    debug(("%4x, ", Len-8));
  420. X
  421. X    if (rawbuf >= rawend) {
  422. X        debug(("short data, EOT %4x\n", Len));
  423. X        goto end;
  424. X    }
  425. X    secptr = trackbuf + MS_BPS * sector;
  426. X    for (numbytes = 0; numbytes < MS_BPS; numbytes++) {
  427. X        *secptr++ = DecodeByte(decode, *rawbuf++);
  428. X    }
  429. X    debug(("%4x\n", Len));
  430. X    oldcrc[sector]    = DecodeByte(decode, *rawbuf++) << 8;
  431. X    oldcrc[sector] |= DecodeByte(decode, *rawbuf++);
  432. X    unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  433. X    }
  434. X
  435. Xend:
  436. X    if (numsecs == 0)
  437. X    return TDERR_TooFewSecs;
  438. X
  439. X#ifndef READONLY
  440. X    /*
  441. X     * If we read the very first track, we adjust our notion about the
  442. X     * number of sectors on each track. This is the only track we can
  443. X     * accurately find if this number is unknown. Let's hope that the first
  444. X     * user of this disk starts reading it here.
  445. X     */
  446. X    if (unit->mu_CurrentTrack == 0 && unit->mu_CurrentSide == 0) {
  447. X    unit->mu_SectorsPerTrack = maxsec;
  448. X    }
  449. X    unit->mu_CurrentSectors = maxsec;
  450. X    debug(("%d sectors\n", unit->mu_SectorsPerTrack));
  451. X#endif
  452. X
  453. X    return 0;
  454. X
  455. X#undef Len
  456. X}
  457. X#else    /* Use assembly */
  458. X
  459. Xint
  460. XDecodeTrack(dev, unit)
  461. XDEV           *dev;
  462. XUNIT           *unit;
  463. X{
  464. X    register word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  465. X    byte       *rawend = (byte *)rawbuf + RLEN - (MS_BPS+2)*sizeof(word);
  466. X    byte       *trackbuf = unit->mu_TrackBuffer;
  467. X    register byte  *decode = dev->md_MfmDecode;     /*  a3 */
  468. X    word       *oldcrc = unit->mu_CrcBuffer;
  469. X    register byte  *secptr;                /*  a4 */
  470. X    long        sector;
  471. X    word        numsecs;
  472. X    register long   numbytes;                /*  d3 */
  473. X    word        maxsec;
  474. X
  475. X#asm
  476. X
  477. XMFM_ID        equ     $5554
  478. XMFM_DATA    equ     $5545
  479. X
  480. Xrawbuf        equr    a2
  481. Xdecode        equr    a3
  482. Xsecptr        equr    a4
  483. Xnumbytes    equr    d3
  484. X
  485. Xrawend        set     -4
  486. Xtrackbuf    set     -8
  487. Xoldcrc        set     -12
  488. Xsector        set     -16
  489. Xnumsecs     set     -18
  490. Xmaxsec        set     -20
  491. X
  492. X    move.w    #0,numsecs(a5)      ; no sectors found yet
  493. X    move.w    #0,maxsec(a5)       ; and no highest sector number
  494. X
  495. X;;;;    First we will try to find a sector id.
  496. Xfind_id:
  497. X    cmp    #SYNC,(rawbuf)+
  498. X    beq.s    fid_gotsync
  499. X    cmpa.l    rawend(a5),rawbuf
  500. X    blt    find_id
  501. X    bra    return            ; We ran off the end of the buffer.
  502. X
  503. Xfid_gotsync:                ; Skip the other syncs.
  504. X    cmp.w    #SYNC,(rawbuf)
  505. X    bne    fid_endsync
  506. X    lea    2(rawbuf),rawbuf
  507. X    bra    fid_gotsync
  508. X
  509. Xfid_endsync:
  510. X    cmp.w    #MFM_ID,(rawbuf)+
  511. X    bne    find_id
  512. X
  513. X    bsr    DecodeByte        ; track #
  514. X    bsr    DecodeByte        ; side #
  515. X    moveq.l #0,d0            ; clear high part
  516. X    bsr    DecodeByte        ; sector #
  517. X    cmp.w    #MS_SPT_MAX,d0        ; sector number too large?
  518. X    bgt    find_id
  519. X    cmp.w    maxsec(a5),d0       ; what is the highest sector number?
  520. X    ble    nomax
  521. X    move.w    d0,maxsec(a5)       ; record the highest sector number
  522. Xnomax:
  523. X    subq.w    #1,d0            ; normalize sector number
  524. X    move.l    d0,sector(a5)
  525. X
  526. Xfind_data:                ; Then find the data block.
  527. X    cmp    #SYNC,(rawbuf)+
  528. X    beq.s    fda_gotsync
  529. X    cmpa.l    rawend(a5),rawbuf
  530. X    blt    find_data
  531. X    bra    return            ; we ran off the end of the buffer.
  532. X
  533. Xfda_gotsync:                ; skip the other syncs.
  534. X    cmp.w    #SYNC,(rawbuf)
  535. X    bne    fda_endsync
  536. X    lea    2(rawbuf),rawbuf
  537. X    bra    fda_gotsync
  538. X
  539. Xfda_endsync:
  540. X    cmp.w    #MFM_DATA,(rawbuf)+ ; do we really have a data block?
  541. X    bne    find_id
  542. X
  543. X    cmpa.l    rawend(a5),rawbuf   ; will we still be inside the mfm data?
  544. X    bge    return
  545. X
  546. X    move.l    sector(a5),d0       ; calculate the location to
  547. X    moveq.l #LOG2_MS_BPS,d1     ;  store this sector.
  548. X    asl.l    d1,d0
  549. X    move.l    trackbuf(a5),secptr
  550. X    add.l    d0,secptr
  551. X
  552. X    move.w    #MS_BPS-1,numbytes
  553. Xdata_copy:
  554. X    bsr    DecodeByte
  555. X    move.b    d0,(secptr)+
  556. X    dbra    numbytes,data_copy
  557. X
  558. X    move.l    sector(a5),d3       ; get pointer to crc location
  559. X    add.l    d3,d3            ; 2 bytes of crc per sector
  560. X    move.l    oldcrc(a5),a0
  561. X    add.l    d3,a0
  562. X
  563. X    bsr    DecodeByte        ; get high byte
  564. X    move.b    d0,(a0)+
  565. X    bsr    DecodeByte        ; and low byte of crc
  566. X    move.b    d0,(a0)+
  567. X
  568. X#endasm
  569. X    unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  570. X#asm
  571. X    addq.w    #1,numsecs(a5)
  572. X    cmp.w    #MS_SPT_MAX,numsecs(a5)
  573. X    blt    find_id
  574. Xreturn:
  575. X#endasm
  576. X
  577. X    if (numsecs == 0)
  578. X    return TDERR_TooFewSecs;
  579. X
  580. X#ifndef READONLY
  581. X    /*
  582. X     * If we read the very first track, we adjust our notion about the
  583. X     * number of sectors on each track. This is the only track we can
  584. X     * accurately find if this number is unknown. Let's hope that the first
  585. X     * user of this disk starts reading it here.
  586. X     */
  587. X    if (unit->mu_CurrentTrack == 0 && unit->mu_CurrentSide == 0) {
  588. X    unit->mu_SectorsPerTrack = maxsec;
  589. X    }
  590. X    unit->mu_CurrentSectors = maxsec;
  591. X    debug(("%d sectors\n", unit->mu_SectorsPerTrack));
  592. X#endif
  593. X
  594. X    return 0;
  595. X
  596. X}
  597. X
  598. X#asm
  599. X;;;;
  600. X;
  601. X;   Decode a single MFM word to a byte.
  602. X;   Auto-increments the rawbuffer pointer.
  603. X
  604. XDecodeByte:
  605. X    move.b    (rawbuf)+,d1    ; high nybble
  606. X    and.w    #$7f,d1     ; strip clock bit (and garbage)
  607. X    move.b    (decode,d1.w),d0; decode 4 data bits
  608. X    lsl.b    #4,d0        ; make room for the rest
  609. X
  610. X    move.b    (rawbuf)+,d1    ; low nybble
  611. X    and.b    #$7f,d1     ; strip clock bit again
  612. X    or.b    (decode,d1.w),d0; insert 4 decoded bits
  613. X
  614. X    rts
  615. X
  616. X#endasm
  617. X#endif    /* using assembly */
  618. X
  619. X/*
  620. X * Initialize the ibm mfm decoding table
  621. X */
  622. X
  623. Xvoid
  624. XInitDecoding(decode)
  625. Xregister byte  *decode;
  626. X{
  627. X    register int    i;
  628. X
  629. X    i = 0;
  630. X    do {
  631. X    decode[i] = 0xff;
  632. X    } while (++i < 128);
  633. X
  634. X    i = 0;
  635. X    do {
  636. X    decode[MfmEncode[i]] = i;
  637. X    } while (++i < 0x10);
  638. X}
  639. X
  640. X#ifdef notdef
  641. Xlong
  642. XMyDoIO(req)
  643. Xregister struct IORequest *req;
  644. X{
  645. X    req->io_Flags |= IOF_QUICK;
  646. X    BeginIO(req);
  647. X    return WaitIO(req);
  648. X}
  649. X#endif
  650. X
  651. X/*
  652. X * Switch the drive motor on. Return previous state. Don't use this when
  653. X * you have allocated the disk via GetDrive().
  654. X */
  655. X
  656. Xint
  657. XTDMotorOn(tdreq)
  658. Xregister struct IOExtTD *tdreq;
  659. X{
  660. X    debug(("TDMotorOn "));
  661. X    tdreq->iotd_Req.io_Command = TD_MOTOR;
  662. X    tdreq->iotd_Req.io_Length = 1;
  663. X    DoIO(tdreq);
  664. X    debug(("was %ld\n", tdreq->iotd_Req.io_Actual));
  665. X
  666. X    return tdreq->iotd_Req.io_Actual;
  667. X}
  668. X
  669. X/*
  670. X * Get the number of cylinders the drive is capable of using.
  671. X */
  672. X
  673. Xint
  674. XTDGetNumCyls(tdreq)
  675. Xregister struct IOExtTD *tdreq;
  676. X{
  677. X    tdreq->iotd_Req.io_Command = TD_GETNUMTRACKS;
  678. X    DoIO(tdreq);
  679. X
  680. X    return tdreq->iotd_Req.io_Actual / NUMHEADS;
  681. X}
  682. X
  683. X/*
  684. X * Seek the drive to the indicated cylinder. Use the trackdisk.device for
  685. X * ease. Don't use this when you have allocated the disk via GetDrive().
  686. X */
  687. X
  688. Xint
  689. XTDSeek(unit, ioreq, cylinder)
  690. XUNIT           *unit;
  691. Xstruct IOStdReq *ioreq;
  692. Xint        cylinder;
  693. X{
  694. X    register struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  695. X
  696. X    debug(("TDSeek %d\n", cylinder));
  697. X
  698. X    tdreq->iotd_Req.io_Command = TD_SEEK;
  699. X    tdreq->iotd_Req.io_Offset = cylinder * (TD_SECTOR * NUMSECS * NUMHEADS);
  700. X    if ((ioreq->io_Flags & IOMDF_40TRACKS) && (unit->mu_NumCyls == 80))
  701. X    tdreq->iotd_Req.io_Offset *= 2;
  702. X    DoIO(tdreq);
  703. X
  704. X    return tdreq->iotd_Req.io_Error;
  705. X}
  706. X
  707. Xvoid           *
  708. XGetDrive(drunit)
  709. Xregister struct DiskResourceUnit *drunit;
  710. X{
  711. X    register void  *LastDriver;
  712. X
  713. X    debug(("GetDrive: "));
  714. X    for (;;) {
  715. X    drunit->dru_Message.mn_Node.ln_Type = NT_MESSAGE;
  716. X    LastDriver = GetUnit(drunit);
  717. X
  718. X    debug(("LastDriver %08lx\n", LastDriver));
  719. X    if (LastDriver) {
  720. X        return LastDriver;
  721. X    } else {
  722. X        while (drunit->dru_Message.mn_Node.ln_Type != NT_REPLYMSG)
  723. X        Wait(1L << drunit->dru_Message.mn_ReplyPort->mp_SigBit);
  724. X        Remove(drunit);
  725. X        debug(("GetDrive: Retry\n"));
  726. X    }
  727. X    }
  728. X}
  729. X
  730. Xvoid
  731. XFreeDrive()
  732. X{
  733. X    GiveUnit();
  734. X}
  735. X
  736. Xint
  737. XGetTrack(ioreq, side, track)
  738. Xstruct IOStdReq *ioreq;
  739. Xint        side;
  740. Xint        track;
  741. X{
  742. X    register int    i;
  743. X    DEV        *dev;
  744. X    register UNIT  *unit;
  745. X
  746. X    debug(("GetTrack %d %d\n", track, side));
  747. X    dev = (DEV *) ioreq->io_Device;
  748. X    unit = (UNIT *) ioreq->io_Unit;
  749. X
  750. X    if (track != unit->mu_CurrentTrack || side != unit->mu_CurrentSide) {
  751. X#ifndef READONLY
  752. X    Internal_Update(ioreq, unit);
  753. X#endif
  754. X    for (i = MS_SPT_MAX-1; i >= 0; i--) {
  755. X        unit->mu_SectorStatus[i] = TDERR_NoSecHdr;
  756. X    }
  757. X
  758. X    TDMotorOn(unit->mu_DiskIOReq);
  759. X    if (TDSeek(unit, ioreq, track)) {
  760. X        debug(("Seek error\n"));
  761. X        return ioreq->io_Error = IOERR_BADLENGTH;
  762. X    }
  763. X    unit->mu_CurrentTrack = track;
  764. X    unit->mu_CurrentSide = side;
  765. X    ObtainSemaphore(&dev->md_HardwareUse);
  766. X    HardwareIO(dev, unit, 0);
  767. X    i = DecodeTrack(dev, unit);
  768. X    ReleaseSemaphore(&dev->md_HardwareUse);
  769. X    debug(("DecodeTrack returns %d\n", i));
  770. X
  771. X    if (i != 0) {
  772. X        unit->mu_CurrentTrack = -1;
  773. X        return i;
  774. X    }
  775. X    }
  776. X
  777. X    return 0;
  778. X}
  779. X
  780. X/*
  781. X * Test if it is changed
  782. X */
  783. X
  784. Xint
  785. XCheckChanged(ioreq, unit)
  786. Xstruct IOExtTD *ioreq;
  787. Xregister UNIT  *unit;
  788. X{
  789. X    register struct IOExtTD *tdreq;
  790. X
  791. X    if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  792. X    ioreq->iotd_Count < unit->mu_ChangeNum) {
  793. Xdiskchanged:
  794. X    ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  795. Xerror:
  796. X    return 1;
  797. X    }
  798. X    return 0;
  799. X}
  800. X
  801. X/*
  802. X * Test if we can read or write the disk. Is it inserted and writable?
  803. X */
  804. X
  805. Xint
  806. XCheckRequest(ioreq, unit)
  807. Xstruct IOExtTD *ioreq;
  808. Xregister UNIT  *unit;
  809. X{
  810. X    register struct IOExtTD *tdreq;
  811. X
  812. X    if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  813. X    ioreq->iotd_Count < unit->mu_ChangeNum) {
  814. Xdiskchanged:
  815. X    ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  816. Xerror:
  817. X    return 1;
  818. X    }
  819. X    /*
  820. X     * if (ioreq->iotd_Req.io_Offset + ioreq->iotd_Req.io_Length >
  821. X     * (unit->mu_NumCyls * MS_NSIDES * MS_SPT * MS_BPS)) {
  822. X     * ioreq->iotd_Req.io_Error = IOERR_BADLENGTH; goto error; }
  823. X     */
  824. X
  825. X    tdreq = unit->mu_DiskIOReq;
  826. X
  827. X    if (unit->mu_DiskState == STATEF_UNKNOWN) {
  828. X    tdreq->iotd_Req.io_Command = TD_PROTSTATUS;
  829. X    DoIO(tdreq);
  830. X    if (tdreq->iotd_Req.io_Error == 0) {
  831. X        if (tdreq->iotd_Req.io_Actual == 0) {
  832. X        unit->mu_DiskState = STATEF_PRESENT | STATEF_WRITABLE;
  833. X        } else
  834. X        unit->mu_DiskState = STATEF_PRESENT;
  835. X    } else
  836. X        unit->mu_DiskState = 0;
  837. X    }
  838. X    if (!(unit->mu_DiskState & STATEF_PRESENT))
  839. X    goto diskchanged;
  840. X
  841. X    /*
  842. X     * Check _WRITE, _UPDATE, _FORMAT
  843. X     */
  844. X    if (STRIP(ioreq->iotd_Req.io_Command) != CMD_READ) {
  845. X    if (!(unit->mu_DiskState & STATEF_WRITABLE)) {
  846. X        ioreq->iotd_Req.io_Error = TDERR_WriteProt;
  847. X        goto error;
  848. X    }
  849. X    }
  850. X    return 0;
  851. X}
  852. X
  853. X
  854. X/*
  855. X * Read zero or more sectors from the disk and copy them into the user's
  856. X * buffer.
  857. X */
  858. X
  859. Xvoid
  860. XCMD_Read(ioreq, unit)
  861. Xregister struct IOExtTD *ioreq;
  862. Xregister UNIT  *unit;
  863. X{
  864. X    int         side;
  865. X    int         cylinder;
  866. X    int         sector;
  867. X    byte       *userbuf;
  868. X    long        length;
  869. X    long        offset;
  870. X    byte       *diskbuf;
  871. X    int         retrycount;
  872. X
  873. X    debug(("CMD_Read "));
  874. X    userbuf = (byte *) ioreq->iotd_Req.io_Data;
  875. X    length = ioreq->iotd_Req.io_Length / MS_BPS;    /* Sector count */
  876. X    offset = ioreq->iotd_Req.io_Offset / MS_BPS;    /* Sector number */
  877. X    debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  878. X
  879. X    cylinder = offset / unit->mu_SectorsPerTrack;
  880. X    side = cylinder % MS_NSIDES;
  881. X    cylinder /= MS_NSIDES;
  882. X    sector = offset % unit->mu_SectorsPerTrack;       /* 0..8 or 9 */
  883. X    debug(("Tr=%d Si=%d Se=%d\n", cylinder, side, sector));
  884. X
  885. X    ioreq->iotd_Req.io_Actual = 0;
  886. X
  887. X    if (length <= 0 || CheckRequest(ioreq, unit))
  888. X    goto end;
  889. X
  890. X    retrycount = 0;
  891. X    diskbuf = unit->mu_TrackBuffer + MS_BPS * sector;
  892. Xgettrack:
  893. X    GetTrack(ioreq, side, cylinder);
  894. X
  895. X    for (;;) {
  896. X    /*
  897. X     * Have we ever checked this CRC?
  898. X     */
  899. X    if (unit->mu_SectorStatus[sector] == CRC_UNCHECKED) {
  900. X        /*
  901. X         * Do it now. If it mismatches, remember that for later.
  902. X         */
  903. X        if (unit->mu_CrcBuffer[sector] != DataCRC(diskbuf)) {
  904. X        debug(("%d: %04x, now %04x\n", sector, unit->mu_CrcBuffer[sector], DataCRC(diskbuf)));
  905. X        unit->mu_SectorStatus[sector] = TDERR_BadSecSum;
  906. X        } else
  907. X        unit->mu_SectorStatus[sector] = TDERR_NoError;
  908. X    }
  909. X    if (unit->mu_SectorStatus[sector] > TDERR_NoError) {
  910. X        if (++retrycount < 3) {
  911. X        unit->mu_CurrentTrack = -1;
  912. X        goto gettrack;
  913. X        }
  914. X        ioreq->iotd_Req.io_Error = unit->mu_SectorStatus[sector];
  915. X        goto end;        /* Don't use this sector anymore... */
  916. X    }
  917. X    retrycount = 0;
  918. X    CopyMem(diskbuf, userbuf, (long) MS_BPS);
  919. X    ioreq->iotd_Req.io_Actual += MS_BPS;
  920. X    if (--length <= 0)
  921. X        break;
  922. X    userbuf += MS_BPS;
  923. X    diskbuf += MS_BPS;
  924. X    if (++sector >= unit->mu_SectorsPerTrack) {
  925. X        sector = 0;
  926. X        diskbuf = unit->mu_TrackBuffer;
  927. X        if (++side >= MS_NSIDES) {
  928. X        side = 0;
  929. X        if (++cylinder >= unit->mu_NumCyls) {
  930. X            /* ioreq->iotd_Req.io_Error = IOERR_BADLENGTH; */
  931. X            goto end;
  932. X        }
  933. X        }
  934. X        GetTrack(ioreq, side, cylinder);
  935. X    }
  936. X    }
  937. X
  938. Xend:
  939. X    TermIO(ioreq);
  940. X}
  941. X
  942. X#ifdef READONLY
  943. X
  944. Xvoid
  945. XCMD_Write(ioreq, unit)
  946. Xregister struct IOExtTD *ioreq;
  947. XUNIT           *unit;
  948. X{
  949. X    ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  950. X    TermIO(ioreq);
  951. X}
  952. X
  953. Xvoid
  954. XTD_Format(ioreq, unit)
  955. Xregister struct IOExtTD *ioreq;
  956. XUNIT           *unit;
  957. X{
  958. X    ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  959. X    TermIO(ioreq);
  960. X}
  961. X
  962. X#endif
  963. X
  964. Xvoid
  965. XCMD_Reset(ioreq, unit)
  966. Xstruct IOExtTD *ioreq;
  967. XUNIT           *unit;
  968. X{
  969. X    unit->mu_CurrentSide = -1;
  970. X    unit->mu_TrackChanged = 0;
  971. X    TermIO(ioreq);
  972. X}
  973. X
  974. Xvoid
  975. XCMD_Update(ioreq, unit)
  976. Xstruct IOExtTD *ioreq;
  977. Xregister UNIT  *unit;
  978. X{
  979. X#ifndef READONLY
  980. X    if (unit->mu_TrackChanged && !CheckRequest(ioreq, unit))
  981. X    Internal_Update(ioreq, unit);
  982. X#endif
  983. X    TermIO(ioreq);
  984. X}
  985. X
  986. Xvoid
  987. XCMD_Clear(ioreq, unit)
  988. Xstruct IOExtTD *ioreq;
  989. XUNIT           *unit;
  990. X{
  991. X    if (!CheckChanged(ioreq, unit)) {
  992. X    unit->mu_CurrentSide = -1;
  993. X    unit->mu_TrackChanged = 0;
  994. X    }
  995. X    TermIO(ioreq);
  996. X}
  997. X
  998. Xvoid
  999. XTD_Seek(ioreq, unit)
  1000. Xstruct IOExtTD *ioreq;
  1001. XUNIT           *unit;
  1002. X{
  1003. X    if (!CheckChanged(ioreq, unit)) {
  1004. X    word        cylinder;
  1005. X
  1006. X    cylinder = (ioreq->iotd_Req.io_Offset / unit->mu_SectorsPerTrack) /
  1007. X            (MS_BPS * MS_NSIDES);
  1008. X    TDSeek(unit, ioreq, cylinder);
  1009. X    }
  1010. X    TermIO(ioreq);
  1011. X}
  1012. X
  1013. X/*
  1014. X * Ask the trackdisk.device for the answer, but keep a local copy.
  1015. X */
  1016. X
  1017. Xvoid
  1018. XTD_Changenum(ioreq, unit)
  1019. Xstruct IOExtTD *ioreq;
  1020. XUNIT           *unit;
  1021. X{
  1022. X    register struct IOStdReq *req;
  1023. X
  1024. X    req = &unit->mu_DiskIOReq->iotd_Req;
  1025. X    req->io_Command = TD_CHANGENUM;
  1026. X    DoIO(req);
  1027. X
  1028. X    unit->mu_ChangeNum = req->io_Actual;
  1029. X    ioreq->iotd_Req.io_Actual = req->io_Actual;
  1030. X    TermIO(ioreq);
  1031. X}
  1032. X
  1033. Xint
  1034. XDevInit(dev)
  1035. Xregister DEV   *dev;
  1036. X{
  1037. X    if (!(DRResource = OpenResource(DISKNAME)))
  1038. X    goto abort;
  1039. X
  1040. X    if (!(CiaBResource = OpenResource(CIABNAME)))
  1041. X    goto abort;
  1042. X
  1043. X#ifndef READONLY
  1044. X    if (!InitWrite(dev))
  1045. X    goto abort;
  1046. X#endif
  1047. X
  1048. X    InitDecoding(dev->md_MfmDecode);
  1049. X    InitSemaphore(&dev->md_HardwareUse);
  1050. X    return 1;            /* Initializing succeeded */
  1051. X
  1052. Xabort:
  1053. X    return DevCloseDown(dev);
  1054. X}
  1055. X
  1056. Xint
  1057. XDevCloseDown(dev)
  1058. XDEV           *dev;
  1059. X{
  1060. X#ifndef READONLY
  1061. X    FreeBuffer(dev);
  1062. X#endif
  1063. X    return 0;            /* Now unitialized */
  1064. X}
  1065. X
  1066. X#ifndef READONLY
  1067. X/*
  1068. X * Calculate the length between the sectors, given the length of the track
  1069. X * and the number of sectors that must fit on it.
  1070. X * The proper formula would be
  1071. X * (((TLEN/2) - INDEXGAP - TAILGAP) / unit->mu_SectorsPerTrack) - BLOCKLEN;
  1072. X */
  1073. X
  1074. Xword
  1075. XCalculateGapLength(sectors)
  1076. Xint        sectors;
  1077. X{
  1078. X    return (sectors == 10) ? DATAGAP3_10 : DATAGAP3_9;
  1079. X}
  1080. X#endif
  1081. X
  1082. XUNIT           *
  1083. XUnitInit(dev, UnitNr)
  1084. XDEV           *dev;
  1085. Xulong        UnitNr;
  1086. X{
  1087. X    register UNIT  *unit;
  1088. X    struct Task    *task;
  1089. X    struct IOStdReq *dcr;
  1090. X    struct IOExtTD *tdreq;
  1091. X
  1092. X    unit = AllocMem((long) sizeof (UNIT), MEMF_PUBLIC | MEMF_CLEAR);
  1093. X    if (unit == NULL)
  1094. X    return NULL;
  1095. X
  1096. X    if (!(tdreq = CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*tdreq)))) {
  1097. X    goto abort;
  1098. X    }
  1099. X    unit->mu_DiskIOReq = tdreq;
  1100. X    if (OpenDevice(TD_NAME, UnitNr, tdreq, TDF_ALLOW_NON_3_5)) {
  1101. X    tdreq->iotd_Req.io_Device = NULL;
  1102. X    goto abort;
  1103. X    }
  1104. X    dcr = (void *) CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*dcr));
  1105. X    if (dcr) {
  1106. X    unit->mu_DiskChangeReq = dcr;
  1107. X    unit->mu_DiskChangeInt.is_Node.ln_Pri = 32;
  1108. X    unit->mu_DiskChangeInt.is_Data = (APTR) unit;
  1109. X    unit->mu_DiskChangeInt.is_Code = DiskChangeHandler;
  1110. X    /* Clone IO request part */
  1111. X    dcr->io_Device = tdreq->iotd_Req.io_Device;
  1112. X    dcr->io_Unit = tdreq->iotd_Req.io_Unit;
  1113. X    dcr->io_Command = TD_ADDCHANGEINT;
  1114. X    dcr->io_Data = (void *) &unit->mu_DiskChangeInt;
  1115. X    SendIO(dcr);
  1116. X    }
  1117. X    NewList(&unit->mu_ChangeIntList);
  1118. X
  1119. X    unit->mu_NumCyls = TDGetNumCyls(tdreq);
  1120. X    unit->mu_UnitNr = UnitNr;
  1121. X    unit->mu_DiskState = STATEF_UNKNOWN;
  1122. X    unit->mu_TrackChanged = 0;
  1123. X    unit->mu_CurrentSide = -1;
  1124. X    unit->mu_InitSectorStatus = CRC_UNCHECKED;
  1125. X    unit->mu_SectorsPerTrack = MS_SPT;
  1126. X
  1127. X    unit->mu_DRUnit.dru_Message.mn_ReplyPort = &unit->mu_DiskReplyPort;
  1128. X    unit->mu_DRUnit.dru_Index.is_Node.ln_Pri = 32; /* high pri for index int */
  1129. X    unit->mu_DRUnit.dru_Index.is_Code = IndexIntCode;
  1130. X    unit->mu_DRUnit.dru_DiscBlock.is_Code = DskBlkIntCode;
  1131. X
  1132. X    /*
  1133. X     * Now create the Unit task. Remember that it won't start running
  1134. X     * since we are Forbid()den. But just to be sure, we Forbid() again.
  1135. X     */
  1136. X    Forbid();
  1137. X    task = CreateTask(DevName, TASKPRI, UnitTask, TASKSTACK);
  1138. X    task->tc_UserData = (APTR) unit;
  1139. X
  1140. X    unit->mu_Port.mp_Flags = PA_IGNORE;
  1141. X    unit->mu_Port.mp_SigTask = task;
  1142. X    NewList(&unit->mu_Port.mp_MsgList);
  1143. X
  1144. X    unit->mu_DiskReplyPort.mp_Flags = PA_IGNORE;
  1145. X    unit->mu_DiskReplyPort.mp_SigTask = task;
  1146. X    NewList(&unit->mu_DiskReplyPort.mp_MsgList);
  1147. X    Permit();
  1148. X
  1149. X    return unit;
  1150. X
  1151. Xabort:
  1152. X    UnitCloseDown(NULL, dev, unit);
  1153. X    return NULL;
  1154. X}
  1155. X
  1156. Xint
  1157. XUnitCloseDown(ioreq, dev, unit)
  1158. Xstruct IOExtTD *ioreq;
  1159. XDEV           *dev;
  1160. Xregister UNIT  *unit;
  1161. X{
  1162. X#ifndef READONLY
  1163. X    if (ioreq && unit->mu_TrackChanged)
  1164. X    Internal_Update(ioreq, unit);
  1165. X#endif
  1166. X
  1167. X    /*
  1168. X     * Get rid of the Unit's task. We know this is safe because the unit
  1169. X     * has an open count of zero, so it is 'guaranteed' not in use.
  1170. X     */
  1171. X
  1172. X    if (unit->mu_Port.mp_SigTask) {
  1173. X#ifdef DEBUG
  1174. X    extern struct SignalSemaphore PortUse;
  1175. X
  1176. X    /*
  1177. X     * Make sure that the unit task does not get removed when it has
  1178. X     * the semaphore.
  1179. X     */
  1180. X    ObtainSemaphore(&PortUse);
  1181. X#endif
  1182. X    RemTask(unit->mu_Port.mp_SigTask);
  1183. X#ifdef DEBUG
  1184. X    ReleaseSemaphore(&PortUse);
  1185. X#endif
  1186. X    }
  1187. X    if (unit->mu_DiskChangeReq) {
  1188. X#if 0                /* V1.2 and V1.3 have a broken
  1189. X                 * TD_REMCHANGEINT */
  1190. X    register struct IOExtTD *req = unit->mu_DiskIOReq;
  1191. X
  1192. X    req->iotd_Req.io_Command = TD_REMCHANGEINT;
  1193. X    req->iotd_Req.io_Data = (void *) unit->mu_DiskChangeReq;
  1194. X    DoIO(req);
  1195. X    WaitIO(unit->mu_DiskChangeReq);
  1196. X#else
  1197. X    Disable();
  1198. X    Remove(unit->mu_DiskChangeReq);
  1199. X    Enable();
  1200. X#endif
  1201. X    DeleteExtIO(unit->mu_DiskChangeReq);
  1202. X    unit->mu_DiskChangeReq = NULL;
  1203. X    }
  1204. X    if (unit->mu_DiskIOReq) {
  1205. X    if (unit->mu_DiskIOReq->iotd_Req.io_Device)
  1206. X        CloseDevice(unit->mu_DiskIOReq);
  1207. X    DeleteExtIO(unit->mu_DiskIOReq);
  1208. X    unit->mu_DiskIOReq = NULL;
  1209. X    }
  1210. X    FreeMem(unit, (long) sizeof (UNIT));
  1211. X
  1212. X    return 0;            /* Now unitialized */
  1213. X}
  1214. X
  1215. X/*
  1216. X * Create missing bindings
  1217. X */
  1218. X/* INDENT OFF */
  1219. X
  1220. X#asm
  1221. X
  1222. Xlib_vectsize    equ    6
  1223. Xlib_base    equ    -lib_vectsize
  1224. X
  1225. X_RVOAllocUnit    equ    lib_base-(0*lib_vectsize)
  1226. X_RVOFreeUnit    equ    lib_base-(1*lib_vectsize)
  1227. X_RVOGetUnit    equ    lib_base-(2*lib_vectsize)
  1228. X_RVOGiveUnit    equ    lib_base-(3*lib_vectsize)
  1229. X_RVOGetUnitID    equ    lib_base-(4*lib_vectsize)
  1230. X
  1231. X;_AllocUnit:
  1232. X;        move.l    _DRResource,a6
  1233. X;        move.l    4(sp),d0
  1234. X;        jmp    _RVOAllocUnit(a6)
  1235. X;_FreeUnit:
  1236. X;        move.l    _DRResource,a6
  1237. X;        move.l    4(sp),d0
  1238. X;        jmp    _RVOFreeUnit(a6)
  1239. X_GetUnit:
  1240. X        move.l    _DRResource,a6
  1241. X        move.l    4(sp),a1
  1242. X        jmp    _RVOGetUnit(a6)
  1243. X;_GetUnitID:
  1244. X;        move.l    _DRResource,a6
  1245. X;        move.l    4(sp),d0
  1246. X;        jmp    _RVOGetUnitID(a6)
  1247. X_GiveUnit:
  1248. X        move.l    _DRResource,a6
  1249. X        jmp    _RVOGiveUnit(a6)
  1250. X
  1251. X#endasm
  1252. X/* INDENT ON */
  1253. X
  1254. X/*
  1255. X * We handle disk change interrupts internally, since the io request is
  1256. X * held by the device. Since SoftInts caused by the trackdisk.device are
  1257. X * broadcast to our clients, our own softint must have the highest
  1258. X * priority possible.
  1259. X *
  1260. X * TD_Addchangeint is an IMMEDIATE command, so no exclusive use of the list
  1261. X * is acquired (nor released). The list is accessed by (software)
  1262. X * interrupt code.
  1263. X */
  1264. X
  1265. Xvoid
  1266. XTD_Addchangeint(ioreq)
  1267. Xregister struct IOStdReq *ioreq;
  1268. X{
  1269. X    register UNIT  *unit;
  1270. X
  1271. X    unit = (UNIT *) ioreq->io_Unit;
  1272. X    Disable();
  1273. X    AddTail(&unit->mu_ChangeIntList, ioreq);
  1274. X    Enable();
  1275. X    ioreq->io_Flags &= ~IOF_QUICK;    /* So we call ReplyMsg instead of
  1276. X                     * TermIO */
  1277. X    /* Note no TermIO */
  1278. X}
  1279. X
  1280. Xvoid
  1281. XTD_Remchangeint(ioreq)
  1282. Xregister struct IOStdReq *ioreq;
  1283. X{
  1284. X    register struct IOStdReq *intreq;
  1285. X
  1286. X    intreq = (struct IOStdReq *) ioreq->io_Data;
  1287. X    Disable();
  1288. X    Remove(intreq);
  1289. X    Enable();
  1290. X    ReplyMsg(&intreq->io_Message);      /* Quick bit always cleared */
  1291. X    ioreq->io_Error = 0;
  1292. X    TermIO(ioreq);
  1293. X}
  1294. X
  1295. Xvoid
  1296. XDiskChangeHandler()
  1297. X{
  1298. X    auto UNIT       *unit;
  1299. X    register struct IOStdReq *ioreq;
  1300. X    register struct IOStdReq *next;
  1301. X/* INDENT OFF */
  1302. X#asm
  1303. X    movem.l d2-d7/a2-a4,-(sp)
  1304. X    move.l  a1,-4(a5)        ;unit
  1305. X#endasm
  1306. X    /* INDENT ON */
  1307. X    unit->mu_DiskState = STATEF_UNKNOWN;
  1308. X    unit->mu_ChangeNum++;
  1309. X    unit->mu_SectorsPerTrack = MS_SPT;
  1310. X    for (ioreq = (struct IOStdReq *) unit->mu_ChangeIntList.mlh_Head;
  1311. X     next = (struct IOStdReq *) ioreq->io_Message.mn_Node.ln_Succ;
  1312. X     ioreq = next) {
  1313. X    Cause((struct Interrupt *) ioreq->io_Data);
  1314. X    }
  1315. X/* INDENT OFF */
  1316. X#asm
  1317. X    movem.l (sp)+,d2-d7/a2-a4
  1318. X#endasm
  1319. X    /* INDENT ON */
  1320. X}
  1321. X
  1322. X#ifndef READONLY
  1323. X
  1324. X/*
  1325. X * Parts of the following code were written by Werner Guenther.
  1326. X * Used with permission.
  1327. X */
  1328. X
  1329. X/* mu_TrackChanged is a flag. When a sector has changed it changes to 1 */
  1330. X
  1331. X/*
  1332. X * InitWrite() has to be called once at startup. It allocates the space
  1333. X * for one raw track, and writes the low level stuff between sectors
  1334. X * (gaps, syncs etc.)
  1335. X */
  1336. X
  1337. Xint
  1338. XInitWrite(dev)
  1339. XDEV           *dev;
  1340. X{
  1341. X    if ((dev->md_Rawbuffer =
  1342. X        AllocMem((long)RLEN+2, MEMF_CHIP | MEMF_PUBLIC)) == 0)
  1343. X    return 0;
  1344. X
  1345. X    return 1;
  1346. X}
  1347. X
  1348. X/*
  1349. X * FreeBuffer has to be called when msh: closes down, it just frees the
  1350. X * memory InitWrite has allocated
  1351. X */
  1352. X
  1353. Xvoid
  1354. XFreeBuffer(dev)
  1355. XDEV           *dev;
  1356. X{
  1357. X    if (dev->md_Rawbuffer) {    /* OIS */
  1358. X    FreeMem(dev->md_Rawbuffer, (long) RLEN + 2);
  1359. X    }
  1360. X}
  1361. X
  1362. X/*
  1363. X * This routine doesn't write to the disk, but updates the TrackBuffer to
  1364. X * respect the new sector. We have to be sure the TrackBuffer is filled
  1365. X * with the current Track. As GetSTS calls Internal_Update if the track
  1366. X * changes we don't have to bother about actually writing any data to the
  1367. X * disk. GetSTS has to be changed in the following way:
  1368. X *
  1369. X * if (track != mu_CurrentTrack || side != mu_CurrentSide) { Internal_Update(); for
  1370. X * (i = 0; i < MS_SPT; i++) ..... etc.
  1371. X */
  1372. X
  1373. Xvoid
  1374. XCMD_Write(ioreq, unit)
  1375. Xregister struct IOExtTD *ioreq;
  1376. XUNIT           *unit;
  1377. X{
  1378. X    int         side;
  1379. X    int         cylinder;
  1380. X    int         sector;
  1381. X    byte       *userbuf;
  1382. X    long        length;
  1383. X    long        offset;
  1384. X    word        spt;
  1385. X
  1386. X    debug(("CMD_Write "));
  1387. X    userbuf = (byte *) ioreq->iotd_Req.io_Data;
  1388. X    length = ioreq->iotd_Req.io_Length / MS_BPS;    /* Sector count */
  1389. X    offset = ioreq->iotd_Req.io_Offset / MS_BPS;    /* Sector number */
  1390. X    debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  1391. X
  1392. X    spt = unit->mu_SectorsPerTrack;
  1393. X    cylinder = offset / spt;
  1394. X    side = cylinder % MS_NSIDES;
  1395. X    cylinder /= MS_NSIDES;
  1396. X    sector = offset % spt;
  1397. X    debug(("T=%d Si=%d Se=%d\n", cylinder, side, sector));
  1398. X
  1399. X    ioreq->iotd_Req.io_Actual = 0;
  1400. X
  1401. X    if (length <= 0 || CheckRequest(ioreq, unit))
  1402. X    goto end;
  1403. X
  1404. X    GetTrack(ioreq, side, cylinder);
  1405. X    for (;;) {
  1406. X    CopyMem(userbuf, unit->mu_TrackBuffer + MS_BPS * sector, (long) MS_BPS);
  1407. X    unit->mu_TrackChanged = 1;
  1408. X    unit->mu_SectorStatus[sector] = CRC_CHANGED;
  1409. X
  1410. X    ioreq->iotd_Req.io_Actual += MS_BPS;
  1411. X    if (--length <= 0)
  1412. X        break;
  1413. X    userbuf += MS_BPS;
  1414. X    /*
  1415. X     * Get next sequential sector/side/track
  1416. X     */
  1417. X    if (++sector >= spt) {
  1418. X        sector = 0;
  1419. X        if (++side >= MS_NSIDES) {
  1420. X        side = 0;
  1421. X        if (++cylinder >= unit->mu_NumCyls)
  1422. X            goto end;
  1423. X        }
  1424. X        GetTrack(ioreq, side, cylinder);
  1425. X    }
  1426. X    }
  1427. X
  1428. X    if (length)
  1429. X    ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  1430. X
  1431. Xend:
  1432. X    TermIO(ioreq);
  1433. X}
  1434. X
  1435. X/*
  1436. X * This is called by your GetSTS() routine if the Track has changed. It
  1437. X * writes the changes back to the disk (a whole track at a time). It has
  1438. X * to be called if your device gets a CLOSE instruction too.
  1439. X */
  1440. X
  1441. Xvoid
  1442. XInternal_Update(ioreq, unit)
  1443. Xstruct IOExtTD *ioreq;
  1444. Xregister UNIT  *unit;
  1445. X{
  1446. X    debug(("Internal_Update "));
  1447. X    /* did we have a changed sector at all     */
  1448. X    if (unit->mu_TrackChanged != 0) {
  1449. X    debug(("needs to write "));
  1450. X
  1451. X    if (unit->mu_SectorsPerTrack > unit->mu_CurrentSectors)
  1452. X        unit->mu_CurrentSectors = unit->mu_SectorsPerTrack;
  1453. X
  1454. X    /*
  1455. X     * Only recalculate the CRC on changed sectors. This way, a
  1456. X     * sector with a bad CRC won't suddenly be ``repaired''.
  1457. X     */
  1458. X    {
  1459. X        register int i;
  1460. X
  1461. X        for (i = unit->mu_CurrentSectors - 1; i >= 0; i--) {
  1462. X        if (unit->mu_SectorStatus[i] == CRC_CHANGED) {
  1463. X            unit->mu_CrcBuffer[i] = DataCRC(unit->mu_TrackBuffer + i * MS_BPS);
  1464. X            debug(("%d: %04x\n", i, unit->mu_CrcBuffer[i]));
  1465. X        }
  1466. X        }
  1467. X    }
  1468. X    {
  1469. X        DEV        *dev;
  1470. X        register struct IOExtTD *tdreq;
  1471. X        word        SectorGap;
  1472. X
  1473. X        dev = (DEV *) ioreq->iotd_Req.io_Device;
  1474. X        tdreq = unit->mu_DiskIOReq;
  1475. X        SectorGap = CalculateGapLength(unit->mu_CurrentSectors);
  1476. X
  1477. X        ObtainSemaphore(&dev->md_HardwareUse);
  1478. X        EncodeTrack(unit->mu_TrackBuffer, dev->md_Rawbuffer,
  1479. X            unit->mu_CrcBuffer,
  1480. X            unit->mu_CurrentTrack, unit->mu_CurrentSide,
  1481. X            SectorGap, unit->mu_CurrentSectors);
  1482. X
  1483. X        TDMotorOn(tdreq);
  1484. X        if (TDSeek(unit, ioreq, unit->mu_CurrentTrack)) {
  1485. X        debug(("Seek error\n"));
  1486. X        ioreq->iotd_Req.io_Error = TDERR_SeekError;
  1487. X        goto end;
  1488. X        }
  1489. X        HardwareIO(dev, unit, DSKWRITE);
  1490. X
  1491. X        ReleaseSemaphore(&dev->md_HardwareUse);
  1492. X        unit->mu_TrackChanged = 0;
  1493. X    }
  1494. X    }
  1495. Xend:
  1496. X    debug(("done\n"));
  1497. X}
  1498. X
  1499. X/*
  1500. X * TD_Format writes one or more whole tracks without reading them first.
  1501. X */
  1502. X
  1503. Xvoid
  1504. XTD_Format(ioreq, unit)
  1505. Xregister struct IOExtTD *ioreq;
  1506. XUNIT           *unit;
  1507. X{
  1508. X    register struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  1509. X    DEV        *dev;
  1510. X    short        side;
  1511. X    int         cylinder;
  1512. X    byte       *userbuf;
  1513. X    int         length;
  1514. X    word        spt;
  1515. X    word        gaplen;
  1516. X
  1517. X    debug(("CMD_Format "));
  1518. X
  1519. X    if (CheckRequest(ioreq, unit))
  1520. X    goto end;
  1521. X
  1522. X    userbuf = (byte *) ioreq->iotd_Req.io_Data;
  1523. X    length = ioreq->iotd_Req.io_Length / MS_BPS;        /* Sector count */
  1524. X    cylinder = ioreq->iotd_Req.io_Offset / MS_BPS;        /* Sector number */
  1525. X    /*
  1526. X     * Now try to guess the number of sectors the user wants per track.
  1527. X     * 40 sectors is the first ambuiguous length.
  1528. X     */
  1529. X    if (length < 40) {
  1530. X    if (length > 0) {
  1531. X        for (spt = 8; spt <= MS_SPT_MAX; spt++) {
  1532. X        if ((length % spt) == 0)
  1533. X            goto found_spt;
  1534. X        }
  1535. X    }
  1536. X    /*
  1537. X     * Not 8, 16, 24, 32, 9, 18, 27, 36, 10, 20, or 30? That is an error.
  1538. X     */
  1539. X    ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  1540. X    goto end;
  1541. X    } else  /* assume previous number */
  1542. X    spt = unit->mu_SectorsPerTrack;
  1543. X
  1544. Xfound_spt:
  1545. X    gaplen = CalculateGapLength(spt);
  1546. X
  1547. X    /*
  1548. X     * Assume the whole disk will have this layout.
  1549. X     */
  1550. X    unit->mu_SectorsPerTrack = spt;
  1551. X
  1552. X    length /= spt;
  1553. X    cylinder /= spt;
  1554. X
  1555. X    side = cylinder % MS_NSIDES;
  1556. X    cylinder /= MS_NSIDES;
  1557. X    debug(("userbuf %08lx cylinder %d len %d\n", userbuf, cylinder, length));
  1558. X
  1559. X    ioreq->iotd_Req.io_Actual = 0;
  1560. X
  1561. X    /*
  1562. X     * Write out the current track if we are not going to overwrite it.
  1563. X     * After the format operation, the buffer is invalidated.
  1564. X     */
  1565. X    if (cylinder <= unit->mu_CurrentTrack &&
  1566. X    unit->mu_CurrentTrack < cylinder + length)
  1567. X    Internal_Update(ioreq, unit);
  1568. X
  1569. X    dev = (DEV *) ioreq->iotd_Req.io_Device;
  1570. X
  1571. X    while (length > 0) {
  1572. X    {
  1573. X        register int i;
  1574. X
  1575. X        for (i = spt - 1; i >= 0; i--) {
  1576. X        unit->mu_CrcBuffer[i] = DataCRC(userbuf + i * MS_BPS);
  1577. X        debug(("%d: %04x\n", i, unit->mu_CrcBuffer[i]));
  1578. X        }
  1579. X    }
  1580. X    ObtainSemaphore(&dev->md_HardwareUse);
  1581. X    EncodeTrack(userbuf, dev->md_Rawbuffer, unit->mu_CrcBuffer,
  1582. X            cylinder, side,
  1583. X            gaplen, spt);
  1584. X
  1585. X    TDMotorOn(tdreq);
  1586. X    if (TDSeek(unit, ioreq, cylinder)) {
  1587. X        debug(("Seek error\n"));
  1588. X        ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  1589. X        break;
  1590. X    }
  1591. X    unit->mu_CurrentSide = side;
  1592. X    HardwareIO(dev, unit, DSKWRITE);
  1593. X
  1594. X    ReleaseSemaphore(&dev->md_HardwareUse);
  1595. X
  1596. X    length--;
  1597. X    userbuf += MS_BPS * spt;
  1598. X    ioreq->iotd_Req.io_Actual += MS_BPS * spt;
  1599. X
  1600. X    if (++side >= MS_NSIDES) {
  1601. X        side = 0;
  1602. X        if (++cylinder >= unit->mu_NumCyls)
  1603. X        goto end;
  1604. X    }
  1605. X    }
  1606. Xend:
  1607. X    unit->mu_CurrentSide = -1;
  1608. X    TermIO(ioreq);
  1609. X}
  1610. X/* INDENT OFF */
  1611. X
  1612. X#asm
  1613. X
  1614. X; we need a buffer for the Sector-ID field to calculate its checksum
  1615. X;SectorHeader:
  1616. X;     dc.b     0           ; track
  1617. X;     dc.b     0           ; side
  1618. X;     dc.b     0           ; sector
  1619. X;     dc.b     2           ; length (2=512 bytes)
  1620. X;     dc.w     0           ; CRC
  1621. X
  1622. X    public _EncodeTrack
  1623. X
  1624. X;   EncodeTrack(TrackBuffer, Rawbuffer, Crcs, Track, Side, GapLen, NumSecs)
  1625. X;        4         4        4     2      2       2       2
  1626. X
  1627. X_EncodeTrack:
  1628. X    movem.l d2-d7/a2-a6,-(sp)  ; save registers
  1629. X
  1630. Xfp    set    (4*(6+5))+4        ; 4 for return address
  1631. Xtrackbf set    0
  1632. Xrawbf    set    4
  1633. Xcrcs    set    8
  1634. Xtrack    set    12
  1635. Xside    set    14
  1636. Xgaplen    set    16
  1637. Xnumsecs set    18
  1638. X
  1639. X; a0    ptr in encoded data (also putmfmbyte)
  1640. X; a2    ptr to mfm encoding table (putmfmbyte)
  1641. X; a3    ptr to data to be crc'd (HeaderCRC)
  1642. X; a4    ptr to table with calculated CRC's
  1643. X; a5    ptr to unencoded data
  1644. X
  1645. X; d0    byte to be encoded (putmfmbyte)
  1646. X; d1    trashed by putmfmbyte
  1647. X; d3    used by putmfmbyte
  1648. X; d5    sector number
  1649. X; d6    general counter of byte spans
  1650. X; d7    sector countdown
  1651. X
  1652. X    sub.w    #2,fp+gaplen(sp)   ; gap length between sectors
  1653. X    move.l    fp+rawbf(sp),a0    ; pointer to mfmencoded buffer
  1654. X    move.l    fp+crcs(sp),a4     ; pointer to precalculated CRCs
  1655. X    move.l    fp+trackbf(sp),a5  ; pointer to unencoded data
  1656. X    lea    _MfmEncode,a2       ; pointer to MFM lookup table
  1657. X
  1658. X    move.w    #$9254,d0       ; a track starts with a gap
  1659. X    moveq    #INDEXGAP-1,d6       ; (60 * $4e)
  1660. Xingl    move.w    d0,(a0)+           ; mfmencoded = $9254
  1661. X    dbf    d6,ingl
  1662. X
  1663. X    lea    -6(sp),sp          ; Reserve room for SectorHeader
  1664. Xfp    set    fp+6
  1665. X    move.w    fp+numsecs(sp),d7  ; number of sectors to encode
  1666. X    subq.w    #1,d7           ; minus 1 for dbra
  1667. X    moveq    #0,d5           ; start with first sector
  1668. X
  1669. Xsecloop:
  1670. X    move.w    #$aaaa,d0       ; a sector starts with a gap containing
  1671. X    moveq    #IDGAP2-1,d6       ; 12 * 0 (mfm = $aaaa)
  1672. Xid2gl    move.w    d0,(a0)+
  1673. X    dbf    d6,id2gl
  1674. X
  1675. X    move.w    #SYNC,d0       ; The ID field begins here, starting
  1676. X    move.w    d0,(a0)+           ; with 3 syncs (3 * $a1) with a missing
  1677. X    move.w    d0,(a0)+           ; clock bit
  1678. X    move.w    d0,(a0)+
  1679. X
  1680. X    move.w    #$5554,(a0)+       ; ID-Address mark ($fe)
  1681. X
  1682. X    move.l    sp,a3           ; pointer to Sector-ID buffer
  1683. X
  1684. X    moveq    #$5554&1,d3       ; preload d3 for the putmfmbyte routine
  1685. X    move.b    fp+track+1(sp),0(a3)  ; insert current track number
  1686. X    move.b    fp+side+1(sp),1(a3)   ; side number
  1687. X    addq.w    #1,d5           ; sectors start with 1 instead of 0
  1688. X    move.b    d5,2(a3)           ; sector number
  1689. X    move.b    #MS_BPScode,3(a3)  ; sector length 512 bytes
  1690. X    bsr    HeaderCRC       ; calculate checksum
  1691. X    move.w    d0,IDDATA(a3)      ; put it past the data
  1692. X
  1693. X    moveq    #IDDATA+IDCRC-1,d6 ; 6 bytes Sector-ID
  1694. Xsidl    move.b    (a3)+,d0           ; get one byte
  1695. X    bsr    putmfmbyte       ; encode it
  1696. X    dbf    d6,sidl        ; end of buffer ?
  1697. X
  1698. X    moveq    #$4e,d0        ; recalculate the MFM value of the
  1699. X    bsr    putmfmbyte       ; first gap byte
  1700. X
  1701. X    moveq    #DATAGAP1-1-1,d6   ; GAP consisting of
  1702. X    move.w    #$9254,d0       ; 22 * $4e
  1703. Xdg1l    move.w    d0,(a0)+
  1704. X    dbf    d6,dg1l
  1705. X
  1706. X    moveq    #DATAGAP2-1,d6       ; GAP consisting of
  1707. X    move.w    #$aaaa,d0       ; 12 * 0 (mfm = $aaaa)
  1708. Xdg2l    move.w    d0,(a0)+
  1709. X    dbf    d6,dg2l
  1710. X
  1711. X    move.w    #SYNC,d0       ; Sector data
  1712. X    move.w    d0,(a0)+           ; starts with 3 syncs
  1713. X    move.w    d0,(a0)+
  1714. X    move.w    d0,(a0)+
  1715. X
  1716. X    move.w    #$5545,(a0)+       ; Data Address Mark ($fb)
  1717. X
  1718. X    moveq    #$5545&1,d3       ; preload d3
  1719. X    move    #MS_BPS-1,d6       ; a sector has 512 bytes
  1720. Xdblockl move.b    (a5)+,d0           ; get one byte from the buffer
  1721. X    bsr    putmfmbyte       ; encode it
  1722. X    dbf    d6,dblockl       ; end of sector ?
  1723. X
  1724. X    move.b    (a4)+,d0           ; get first byte of CRC
  1725. X    bsr    putmfmbyte       ; encode it
  1726. X    move.b    (a4)+,d0           ; get second byte
  1727. X    bsr    putmfmbyte       ; encode it
  1728. X
  1729. X    moveq    #$4e,d0        ; recalculate the MFM value of the
  1730. X    bsr    putmfmbyte       ; first gap byte -> -1 in following loop
  1731. X
  1732. X;    moveq    #DATAGAP3-1-1,d6   ; sector ends with a gap
  1733. X    move.w    fp+gaplen(sp),d6   ; sector ends with a gap, -1 for dbf
  1734. X    move.w    #$9254,d0       ; 80 * $4e
  1735. Xdg3l    move.w    d0,(a0)+
  1736. X    dbf    d6,dg3l
  1737. X
  1738. X    dbf    d7,secloop       ; next sector. d5 has been incremented
  1739. X
  1740. X    lea    6(sp),sp           ; Free room for SectorHeader
  1741. Xfp    set    fp-6
  1742. X
  1743. X    move.l    fp+rawbf(sp),d6    ; pointer to mfmencoded buffer
  1744. X    add.l    #WLEN,d6       ; end of encoded buffer
  1745. X    move.l    a0,d0           ; (I really want to   sub.l a0,d6 )
  1746. X    sub.l    d0,d6           ; length of the remains
  1747. X    lsr.l    #1,d6           ; turn into words
  1748. X
  1749. X    move.w    #$9254,d0       ; Fill the end of the track with $4e
  1750. Xendgl    move.w    d0,(a0)+           ; $9254 mfm encoded
  1751. X    dbf    d6,endgl
  1752. X
  1753. X    movem.l (sp)+,d2-d7/a2-a6
  1754. X    rts
  1755. X
  1756. X; putmfmbyte encodes one byte (in D0) into MSDOS MFM format to the location
  1757. X; pointed by A0. D3 has to be preserved between calls !
  1758. X; A2 must contain the pointer to the encoding table.
  1759. X; Destroys D0, D1. Updates A0 and D3. Requires A0, D0, D3.
  1760. X
  1761. Xputmfmbyte
  1762. X    moveq    #16-4,d1
  1763. X    lsl.l    d1,d0        ; split the byte into two nibbles
  1764. X    lsr.w    d1,d0        ; low nibble is in bits 0..15
  1765. X                ; high nibble in bits 16..31
  1766. X    swap    d0        ; process high nibble first
  1767. X    and.w    #$0f,d0     ; mask out unwanted bits
  1768. X    move.b    0(a2,d0.w),d1   ; get mfmencoded nibble from table
  1769. X    btst    #6,d1        ; we now have to work out if
  1770. X    bne.s    1$        ; the high bit of the unencoded data
  1771. X    btst    #0,d3        ; byte and the low bit of the last
  1772. X    bne.s    1$        ; encoded data are both 0. if this is the
  1773. X    bset    #7,d1        ; case the first clock bit has to be '1'
  1774. X1$    move.b    d1,(a0)+        ; write high (encoded) nibble
  1775. X    swap    d0        ; process low nibble
  1776. X    move.b    0(a2,d0.w),d3   ; ....same as above
  1777. X    btst    #6,d3
  1778. X    bne.s    2$
  1779. X    btst    #0,d1
  1780. X    bne.s    2$
  1781. X    bset    #7,d3
  1782. X2$    move.b    d3,(a0)+
  1783. X    rts
  1784. X
  1785. X#endasm
  1786. X#endif                /* READONLY */
  1787. X#asm
  1788. X
  1789. X; The CRC is computed not only over the actual data, but including
  1790. X; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
  1791. X; As we don't read or encode these fields into our buffers, we have to
  1792. X; preload the registers containing the CRC with the values they would have
  1793. X; after stepping over these fields.
  1794. X;
  1795. X; How CRCs "really" work:
  1796. X;
  1797. X; First, you should regard a bitstring as a series of coefficients of
  1798. X; polymomials. We calculate with these polynomials in modulo-2
  1799. X; arithmetic, in which both add and subtract are done the same as
  1800. X; exclusive-or. Now, we modify our data (a very long polynomial) in
  1801. X; such a way that it becomes divisible by the CCITT-standard 16-bit
  1802. X;         16   12   5
  1803. X; polynomial:    x  + x    + x + 1, represented by $11021. The easiest
  1804. X; way to do this would be to multiply (using proper arithmetic) our
  1805. X; datablock with $11021. So we have:
  1806. X;   data * $11021         =
  1807. X;   data * ($10000 + $1021)      =
  1808. X;   data * $10000 + data * $1021
  1809. X; The left part of this is simple: Just add two 0 bytes. But then
  1810. X; the right part (data $1021) remains difficult and even could have
  1811. X; a carry into the left part. The solution is to use a modified
  1812. X; multiplication, which has a result that is not correct, but with
  1813. X; a difference of any multiple of $11021. We then only need to keep
  1814. X; the 16 least significant bits of the result.
  1815. X;
  1816. X; The following algorithm does this for us:
  1817. X;
  1818. X;   unsigned char *data, c, crclo, crchi;
  1819. X;   while (not done) {
  1820. X;    c = *data++ + crchi;
  1821. X;    crchi = (@ c) >> 8 + crclo;
  1822. X;    crclo = @ c;
  1823. X;   }
  1824. X;
  1825. X; Remember, + is done with EOR, the @ operator is in two tables (high
  1826. X; and low byte separately), which is calculated as
  1827. X;
  1828. X;      $1021 * (c & $F0)
  1829. X;  xor $1021 * (c & $0F)
  1830. X;  xor $1021 * (c >> 4)         (* is regular multiplication)
  1831. X;
  1832. X;
  1833. X; Anyway, the end result is the same as the remainder of the division of
  1834. X; the data by $11021. I am afraid I need to study theory a bit more...
  1835. X
  1836. X
  1837. X; This is the entry to calculate the checksum for the sector-id field
  1838. X; requires:  a3 = pointer to the unencoded data
  1839. X; returns:   d0 = CRC
  1840. X
  1841. XHeaderCRC:
  1842. X    movem.l  d1-d3/a3-a5,-(sp) ; save registers
  1843. X    move.w     #$b2,d0       ; preload registers
  1844. X    moveq     #$30,d1       ; (CRC for $a1,$a1,$a1,$fb)
  1845. X    moveq     #3,d3           ; calculate checksum for 4 bytes
  1846. X    bra.s     getCRC        ; (=track,side,sector,sectorlength)
  1847. X
  1848. X; This is the entry to calculate the checksum for the data field
  1849. X; requires:  a3 = pointer to the unencoded data
  1850. X; returns:   d0 = CRC
  1851. X
  1852. XDataCRC:
  1853. X    movem.l  d1-d3/a3-a5,-(sp) ; save registers
  1854. X    bra.s    DataCRC1
  1855. X
  1856. X; C entry point for DataCRC(byte *data)
  1857. X
  1858. X_DataCRC:
  1859. X    movem.l d1-d3/a3-a5,-(sp) ; save registers
  1860. Xfp    set    (4*(3+3))+4
  1861. Xdata    set    0
  1862. X    move.l    fp+data(sp),a3    ; get parameter
  1863. XDataCRC1:
  1864. X    move.w     #$e2,d0       ; preload the CRC registers
  1865. X    move.w     #$95,d1       ; (CRC for $a1,$a1,$a1,$fe)
  1866. X    move.w     #MS_BPS-1,d3       ; a sector 512 bytes
  1867. X
  1868. XgetCRC    lea     CRCTable1,a4
  1869. X    lea     CRCTable2,a5
  1870. X    moveq     #0,d2
  1871. X
  1872. X1$    move.b     (a3)+,d2
  1873. X    eor.b     d0,d2
  1874. X    move.b     0(a4,d2.w),d0
  1875. X    eor.b     d1,d0
  1876. X    move.b     0(a5,d2.w),d1
  1877. X    dbf     d3,1$
  1878. X
  1879. X    lsl.w     #8,d0
  1880. X    move.b     d1,d0
  1881. X    movem.l  (sp)+,d1-d3/a3-a5
  1882. X    rts
  1883. X
  1884. X
  1885. XCRCTable1:
  1886. X    dc.b $00,$10,$20,$30,$40,$50,$60,$70,$81,$91,$a1,$b1,$c1,$d1,$e1,$f1
  1887. X    dc.b $12,$02,$32,$22,$52,$42,$72,$62,$93,$83,$b3,$a3,$d3,$c3,$f3,$e3
  1888. X    dc.b $24,$34,$04,$14,$64,$74,$44,$54,$a5,$b5,$85,$95,$e5,$f5,$c5,$d5
  1889. X    dc.b $36,$26,$16,$06,$76,$66,$56,$46,$b7,$a7,$97,$87,$f7,$e7,$d7,$c7
  1890. X    dc.b $48,$58,$68,$78,$08,$18,$28,$38,$c9,$d9,$e9,$f9,$89,$99,$a9,$b9
  1891. X    dc.b $5a,$4a,$7a,$6a,$1a,$0a,$3a,$2a,$db,$cb,$fb,$eb,$9b,$8b,$bb,$ab
  1892. X    dc.b $6c,$7c,$4c,$5c,$2c,$3c,$0c,$1c,$ed,$fd,$cd,$dd,$ad,$bd,$8d,$9d
  1893. X    dc.b $7e,$6e,$5e,$4e,$3e,$2e,$1e,$0e,$ff,$ef,$df,$cf,$bf,$af,$9f,$8f
  1894. X    dc.b $91,$81,$b1,$a1,$d1,$c1,$f1,$e1,$10,$00,$30,$20,$50,$40,$70,$60
  1895. X    dc.b $83,$93,$a3,$b3,$c3,$d3,$e3,$f3,$02,$12,$22,$32,$42,$52,$62,$72
  1896. X    dc.b $b5,$a5,$95,$85,$f5,$e5,$d5,$c5,$34,$24,$14,$04,$74,$64,$54,$44
  1897. X    dc.b $a7,$b7,$87,$97,$e7,$f7,$c7,$d7,$26,$36,$06,$16,$66,$76,$46,$56
  1898. X    dc.b $d9,$c9,$f9,$e9,$99,$89,$b9,$a9,$58,$48,$78,$68,$18,$08,$38,$28
  1899. X    dc.b $cb,$db,$eb,$fb,$8b,$9b,$ab,$bb,$4a,$5a,$6a,$7a,$0a,$1a,$2a,$3a
  1900. X    dc.b $fd,$ed,$dd,$cd,$bd,$ad,$9d,$8d,$7c,$6c,$5c,$4c,$3c,$2c,$1c,$0c
  1901. X    dc.b $ef,$ff,$cf,$df,$af,$bf,$8f,$9f,$6e,$7e,$4e,$5e,$2e,$3e,$0e,$1e
  1902. X
  1903. XCRCTable2:
  1904. X    dc.b $00,$21,$42,$63,$84,$a5,$c6,$e7,$08,$29,$4a,$6b,$8c,$ad,$ce,$ef
  1905. X    dc.b $31,$10,$73,$52,$b5,$94,$f7,$d6,$39,$18,$7b,$5a,$bd,$9c,$ff,$de
  1906. X    dc.b $62,$43,$20,$01,$e6,$c7,$a4,$85,$6a,$4b,$28,$09,$ee,$cf,$ac,$8d
  1907. X    dc.b $53,$72,$11,$30,$d7,$f6,$95,$b4,$5b,$7a,$19,$38,$df,$fe,$9d,$bc
  1908. X    dc.b $c4,$e5,$86,$a7,$40,$61,$02,$23,$cc,$ed,$8e,$af,$48,$69,$0a,$2b
  1909. X    dc.b $f5,$d4,$b7,$96,$71,$50,$33,$12,$fd,$dc,$bf,$9e,$79,$58,$3b,$1a
  1910. X    dc.b $a6,$87,$e4,$c5,$22,$03,$60,$41,$ae,$8f,$ec,$cd,$2a,$0b,$68,$49
  1911. X    dc.b $97,$b6,$d5,$f4,$13,$32,$51,$70,$9f,$be,$dd,$fc,$1b,$3a,$59,$78
  1912. X    dc.b $88,$a9,$ca,$eb,$0c,$2d,$4e,$6f,$80,$a1,$c2,$e3,$04,$25,$46,$67
  1913. X    dc.b $b9,$98,$fb,$da,$3d,$1c,$7f,$5e,$b1,$90,$f3,$d2,$35,$14,$77,$56
  1914. X    dc.b $ea,$cb,$a8,$89,$6e,$4f,$2c,$0d,$e2,$c3,$a0,$81,$66,$47,$24,$05
  1915. X    dc.b $db,$fa,$99,$b8,$5f,$7e,$1d,$3c,$d3,$f2,$91,$b0,$57,$76,$15,$34
  1916. X    dc.b $4c,$6d,$0e,$2f,$c8,$e9,$8a,$ab,$44,$65,$06,$27,$c0,$e1,$82,$a3
  1917. X    dc.b $7d,$5c,$3f,$1e,$f9,$d8,$bb,$9a,$75,$54,$37,$16,$f1,$d0,$b3,$92
  1918. X    dc.b $2e,$0f,$6c,$4d,$aa,$8b,$e8,$c9,$26,$07,$64,$45,$a2,$83,$e0,$c1
  1919. X    dc.b $1f,$3e,$5d,$7c,$9b,$ba,$d9,$f8,$17,$36,$55,$74,$93,$b2,$d1,$f0
  1920. X
  1921. X#endasm
  1922. X
  1923. X/* INDENT ON */
  1924. END_OF_FILE
  1925. if test 47667 -ne `wc -c <'src/devio.c'`; then
  1926.     echo shar: \"'src/devio.c'\" unpacked with wrong size!
  1927. fi
  1928. # end of 'src/devio.c'
  1929. fi
  1930. echo shar: End of archive 6 \(of 6\).
  1931. cp /dev/null ark6isdone
  1932. MISSING=""
  1933. for I in 1 2 3 4 5 6 ; do
  1934.     if test ! -f ark${I}isdone ; then
  1935.     MISSING="${MISSING} ${I}"
  1936.     fi
  1937. done
  1938. if test "${MISSING}" = "" ; then
  1939.     echo You have unpacked all 6 archives.
  1940.     rm -f ark[1-9]isdone
  1941. else
  1942.     echo You still need to unpack the following archives:
  1943.     echo "        " ${MISSING}
  1944. fi
  1945. ##  End of shell archive.
  1946. exit 0
  1947. -- 
  1948. Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
  1949. Mail comments to the moderator at <amiga-request@cs.odu.edu>.
  1950. Post requests for sources, and general discussion to comp.sys.amiga.
  1951.